package com.lagou.gateway.filter;

import com.lagou.gateway.feign.CodeFeignClient;
import com.lagou.gateway.feign.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Component
public class RegisterCountLimitFilter implements GlobalFilter {

    @Value("${register.limit.count}")
    private Integer limitCount;

    @Value("${register.limit.minute}")
    private Integer limitMinute;

    @Autowired
    private CodeFeignClient codeFeignClient;

    @Autowired
    private UserFeignClient userFeignClient;

    private Map<String, CopyOnWriteArrayList<Long>> limitMap = new ConcurrentHashMap<>();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        String path = request.getURI().getPath();

        if(path.startsWith("/user/register")) {
            String[] pathArr = path.split("/");
            boolean isRegistered = userFeignClient.isRegistered(pathArr[3]);
            if(isRegistered) {
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.SEE_OTHER);
                String data = "this email is already registered，use another";
                DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                return response.writeWith(Mono.just(wrap));
            }

            Integer isValidatedCode = codeFeignClient.validateCode(pathArr[3], pathArr[5]);
            if(isValidatedCode != 0) {
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.SEE_OTHER);
                String data = "code error";
                DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                return response.writeWith(Mono.just(wrap));
            }


            String clientIp = request.getRemoteAddress().getHostString();

            if(limitMap.containsKey(clientIp)) {
                long currentTime = System.currentTimeMillis();
                List<Long> list = limitMap.get(clientIp);
                list.add(currentTime);

                Iterator<Long> iterator = list.iterator();
                int count = 0;
                while(iterator.hasNext()) {
                    Long putTime = iterator.next();
                    if(putTime + limitMinute * 60 * 1000 >= currentTime) {
                        count++;
                    }
                }

                if(count > limitCount.intValue()) {
                    for(Long putTime : list) {
                        if(putTime + limitMinute * 60 * 1000 >= currentTime) {
                            list.remove(putTime);
                            count--;
                            if(count <= limitCount) {
                                break;
                            }
                        }
                    }

                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    String data = "register frequently，request denied";
                    DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                    return response.writeWith(Mono.just(wrap));
                }
            } else {
                CopyOnWriteArrayList<Long> list = new CopyOnWriteArrayList<>();
                list.add(System.currentTimeMillis());
                limitMap.put(clientIp, list);
            }
        }

        if(path.startsWith("/user/info/")) {
            List<HttpCookie> token = request.getCookies().get("token");
            if(token == null || token.size() <= 0) {
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                String data = "请先登录后再访问";
                DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                return response.writeWith(Mono.just(wrap));
            }

        }



        return chain.filter(exchange);
    }
}
